﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace PerformanceDude.MSBuildShellExtension.Common
{
    public class ProcessRunner
    {
        public string File { get; set; }
        public string Arguments { get; set; }
        public string Verb { get; set; }
        public string WorkingDirectory { get; set; }
        public ProcessWindowStyle WindowStyle { get; set; }
        public bool UseShellExecute { get; set; }
        public bool RedirectOutput { get; set; }

        public StringBuilder Output = new StringBuilder();
        public StringBuilder Error = new StringBuilder();

        public ProcessRunner(string file, string arguments)
        {
            this.File = file;
            this.Arguments = arguments;
            this.WindowStyle = ProcessWindowStyle.Normal;
            this.RedirectOutput = true;
        }

        public int Run()
        {
            Process process = new Process
            {
                StartInfo =
                {
                    FileName = this.File,
                    Verb = this.Verb,
                    WorkingDirectory = this.WorkingDirectory,
                    Arguments = this.Arguments,
                    WindowStyle = this.WindowStyle,
                    UseShellExecute = this.UseShellExecute,
                    RedirectStandardOutput = this.RedirectOutput,
                    RedirectStandardError = this.RedirectOutput
                }
            };

            this.Output = new StringBuilder();
            this.Error = new StringBuilder();

            using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
            using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false))
            {
                process.OutputDataReceived += (sender, e) =>
                {
                    if (e.Data == null)
                    {
                        outputWaitHandle.Set();
                    }
                    else
                    {
                        this.Output.AppendLine(e.Data);
                    }
                };

                process.ErrorDataReceived += (sender, e) =>
                {
                    if (e.Data == null)
                    {
                        errorWaitHandle.Set();
                    }
                    else
                    {
                        this.Error.AppendLine(e.Data);
                    }
                };

                process.Start();
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();
                process.WaitForExit();

                outputWaitHandle.WaitOne();
                errorWaitHandle.WaitOne();
            }

            return process.ExitCode;
        }
    }
}
